
object charpter02 {
  /*
   * 2.1 
   * 一个数字如果为正数，则它的signum为1;
   * 如果是负数,则signum为-1;
   * 如果为0,则signum为0.编写一个函数来计算这个值
   * */
  //  def signum(x: Int): Int = {
  //    if (x > 0) { 1 }
  //    else if (x < 0) { -1 }
  //    else { 0 }
  //  }
  //  def signum(x: Int): Int = if (x > 0) 1 else if (x < 0) -1 else 0;
  //  def signum(x: Int) = { if (x > 0) 1 else if (x < 0) -1 else 0 }
  def signum(x: Int) = if (x > 0) 1 else if (x < 0) -1 else 0

  def main(args: Array[String]): Unit = {
    println(charpter02.signum(10))
  }
  /*
   * 2.2 
   * 一个空的块表达式{}的值是什么？类型是什么？
   * */
  //  def checkEmptyBlockType() = {
  //    println({});
  //    println({}.getClass())
  //  }
  def checkEmptyBlockType { println({}); println({}.getClass()) }

  /*
   * 2.3 
   * 指出在Scala中何种情况下赋值语句x=y=1是合法的。
   * (提示：给x找个合适的类型定义)
   */
  def checkAssignLegal {
    var x: Unit = ()
    println("x's type is: " + x.getClass)
    var y = 1
    x = y = 1
  }

  /*
   * 2.4 
   * 针对下列Java循环编写一个Scala版本:
   * for(int i=10;i>=0;i–)System.out.println(i);
   */
  def ScalaForeach {
    //    1.to(10).reverse.foreach { (i: Int) => Predef.println(i) }
    //    1.to(10).reverse.foreach { i => Predef println i }
    //    1.to(10).reverse.foreach { i => println(i) }
    //    1.to(10).reverse foreach { println _ }
    (1 to 10 reverse) foreach println
  }

  /*
   * 2.5 
   * 编写一个过程countdown(n:Int)，打印从n到0的数字
   */
  def countdown(n: Int) {
    n match {
      case n if n >= 0 => {
        (0 to n reverse) foreach println
      }
      case n if n < 0 => {
        n to 0 foreach println
      }
    }
  }

  /*
   * 2.6 
   * 编写一个for循环,计算字符串中所有字母的Unicode代码的乘积。
   * 举例来说，"Hello"中所有字符串的乘积为9415087488L
   */
  def calculateCharsUnicodeProduct(s: String) = {
    var res: Long = 1
    s foreach { res *= _.toLong }
    res
  }

  /*
   * 2.7 
   * 同样是解决前一个练习的问题，但这次不使用循环。
   * （提示：在Scaladoc中查看StringOps）
   */
  //  def computeCharsUnicodeProduct(s: String) = (1.toLong /: s) { _ * _ }
  def computeCharsUnicodeProduct(s: String) = s.foldLeft(1.toLong) { _ * _ }
  // 这三个函数接收一个参数（初始值）和一个函数，这个函数有两个参数，分别代表上一次计算结果和遍历对象
  // 第一次计算时是拿初始值和遍历对象的第一个元素
  // 如果是List(-3,-2,-1,0,1,2,3).foldLeft(0)(_+_),第一次计算是拿0+(-3)，第2次是拿前一次的结果和遍历的后一个对象相加
  // Array.foldLeft(param)(func)，是先将param传入func，和Array的第一个元素进行计算，即：val result = func(param,Array(1))，第二次计算就是：val result = func(result,Array(2))。。。
  // 而Array.foldRight(param)(func)，不同的是Array元素是从右边开始算的，而且func两个参数取值和foldLeft相反：即第一次计算：val result = func(Array(5),param)（假定Array有5个元素，序号从1开始），第二次计算val result = func(Array(4), result) 。。。

  // fold函数的返回类型是AnyVal，计算次序是不确定的？？所以不常用，也不好用，如果是加和乘的话看不出来结果，减和除就能看出结果
  // fold,foldLeft,foldRight三个函数有两个限制：
  // 1，补始值必须是遍历对象的元素类型的超类
  // 2，补始值必须是中立的，也就是它不能改变结果
  /*
   * 2.8 
   * 编写一个函数product(s:String)，
   * 计算前面练习中提到的乘积
   */
def product(s:String):Long = {
val r = s.foldLeft(1L)(_*_)
r
}


   /**
   
   * 2.9 
   * 把前一个练习中的函数改成递归函数
   */
  //  def product(s: String) = {
  //    if (s.length() == 1) {
  //      s(0) toLong
  //    } else {
  //      s(0).toLong * product(s.tail)
  //    }
  //  }
 // 这几个方法有很多坑，其中一个最主要的，就是必须拿Char去计算，不能用String计算。就算s到最后只剩一位了，也要用s.head将它传化为Char
 // 而s.head和s(0)的返回值就是Char
def product(s:String):Long = {
if (s.length==1) s.head.toLong
else s.head.toLong*product(s.tail)
}

  def product(s: String): Long = {
    if (s.length() == 1) s(0) toLong
    else s(0).toLong * product(s.tail)
  }

  /*
   * 2.10 
   * 编写函数计算x^n,其中n是整数，使用如下的递归定义:
	如果n是正偶数，x^n = y^2
	如果n是正奇数，x^n = x*x^(n-1)
	x^0=1
	如果n是负数，x^n = x^(-n)


   */
def q10(x:Int, n:Int):Double = n match {
case 0 => 1
case n if n < 0 => 1 / q10(x,-n)
case n if n % 2 == 0 => math.pow(q10(x,n/2),2)
case n if n % 2 == 1 => q10(x,n-1) * x
}



  def question10(x: Int, n: Int): BigInt = n match {
    case 0 => 1
    case n if n < 0 => 1 / question10(x, -n)
    case n if n % 2 == 0 => question10(x, n / 2) pow 2
    case n if n % 2 == 1 => x * question10(x, n - 1)
  }

}

/**
	附加几个match的练习：
**/

def match1(i:Int):String = i match {
case i if i == 0 => "the parameter is 0"
case i if i < 0 => "the parameter is below 0"
case i if i > 0 => "the parameter is above 0"
}

def match2(score:Int):String = score match {
case score if score > 90 => "Excellect"
case score if score > 75 => "Wonderful"
case score if score > 60 => "Good"
case _ => "This is Bad"
}
